import { forEach as _forEach, uniqueId as _uniqueId } from 'lodash';
import { flatMap as lvFlatMap, FilterUtils } from '../core/api';
import { TreeNode, TreeFilterConfig as FilterConfig, FlattenNode, TreeNodeKey, TreeNodeExtra } from './interface';

let _flatTreeMap;

// 平铺树
export function setFlatTreeMap(nodes: TreeNode[], pathFn?): void {
  _flatTreeMap = lvFlatMap(nodes, pathFn, true);
}

export function getFlatTreeMap(): any {
  return _flatTreeMap;
}

// 搜索并展开节点
export function searchExpanded(data: TreeNode[], filter: FilterConfig, expanded: boolean): void {
  const expandedNodes: TreeNode[] = [];
  const matchNodes: TreeNode[] = [];

  const expandParent = (item: TreeNode): void => {
    const parentNode = item.parent;
    if (parentNode) {
      expandedNodes.push(parentNode);
      expandParent(parentNode);
    }
  };

  const searchChild = (node: TreeNode): void => {
    const item = node as any;
    const res = filterTool(item, filter);
    if (res.length) {
      expandParent(item);
      matchNodes.push(node);
    }
    _forEach(item.children, (child): void => {
      searchChild(child);
    });
  };

  _forEach(data, (item): void => {
    searchChild(item);
  });

  // 重新设置hidden
  setHiddenNode(matchNodes);

  if (!expanded) {
    return;
  }
  // 重新设置expanded
  setExpandedNode(expandedNodes);
}

function filterTool(data, filter): any {
  const tureValue = [0]; // 默认都匹配
  if (!filter || !Object.keys(filter).length) {
    return tureValue;
  }
  const fn = filter.customItemFilter;
  if (fn) {
    const res = fn(data, filter);
    return res ? [res] : [];
  } else if (!FilterUtils[filter.filterMode]) {
    return tureValue;
  } else {
    return FilterUtils[filter.filterMode]([data], filter);
  }
}

function setExpandedNode(nodes: TreeNode[]): void {
  if (!nodes.length) {
    return;
  }
  const treeMap = getFlatTreeMap();
  // init
  _forEach(getMap(treeMap), (item): false => (item.expanded = false));
  _forEach(nodes, (item): void => {
    item.expanded = true;
  });
}

function setHiddenNode(nodes: TreeNode[]): void {
  const treeMap = getFlatTreeMap();
  // init
  _forEach(getMap(treeMap), (item): true => (item.hidden = true));

  if (!nodes.length) {
    return;
  }

  const hiddenParentNode = (data: TreeNode): void => {
    if (!data) {
      return;
    }
    data.hidden = false;
    hiddenParentNode(data.parent);
  };

  const hiddenChildrenNode = (data: TreeNode): void => {
    _forEach(data, (item): void => {
      item.hidden = false;
      hiddenChildrenNode(item.children);
    });
  };

  _forEach(nodes, (item): void => {
    item.hidden = false;
    hiddenParentNode(item.parent);
    hiddenChildrenNode(item.children);
  });
}

function getMap(data): any[] {
  return Array.from(data.values());
}

// 获取节点所有子孙
export function getDescendants(data: TreeNode, childrenKey: string = 'children'): any[] {
  const nodes = [];
  const getChildrend = (node): void => {
    if (!node) {
      return;
    }
    const children = node[childrenKey] || [];
    nodes.push(...children);
    children.forEach(getChildrend);
  };
  getChildrend(data);
  return nodes;
}

/**
 * 将嵌套树数据平铺，这用于虚拟列表渲染。
 * @param treeNodeList 可视数据（源数据过滤后）
 * @param expandedKeys 需要展开的节点key，如果是true，则表示所有node都需要展开
 * @param extra 额外的参数，目前包含getNodeLevel是否获取节点的层级，默认为false
 */
export function flattenTreeData(
  treeNodeList: TreeNode[] = [],
  expandedKeys: TreeNodeKey[] | true = [],
  extra: TreeNodeExtra = { getNodeLevel: false },
): FlattenNode[] {
  const expandedKeySet = new Set(expandedKeys === true ? [] : expandedKeys);
  const flattenList: FlattenNode[] = [];

  const dig = (list: TreeNode[], parent: FlattenNode | null = null): FlattenNode[] =>
    list.map((treeNode, index): FlattenNode => {
      const pos: string = getPosition(parent ? parent.pos : '0', index);
      const mergedKey = getKey(treeNode.key, pos);
      treeNode._lv_isStart = [...(parent ? parent._lv_isStart : []), index === 0];
      treeNode._lv_isEnd = [...(parent ? parent._lv_isEnd : []), index === list.length - 1];
      treeNode._lv_id = treeNode?._lv_id || _uniqueId();
      // 添加平铺节点数据到list中
      // NEED_DO: 这里只需要data
      const flattenNode: FlattenNode = {
        parent,
        pos,
        children: [],
        data: treeNode,
        _lv_isStart: [...(parent ? parent._lv_isStart : []), index === 0],
        _lv_isEnd: [...(parent ? parent._lv_isEnd : []), index === list.length - 1],
        _lv_id: treeNode._lv_id,
      };

      if (extra.getNodeLevel) {
        const level = parent ? parent._lv_level + 1 : 0;
        treeNode._lv_level = level;
        flattenNode._lv_level = level;
      }

      flattenList.push(flattenNode);

      // 循环树节点子节点
      if (expandedKeys === true || expandedKeySet.has(mergedKey) || treeNode.expanded) {
        flattenNode.children = dig(treeNode.children || [], flattenNode);
      } else {
        flattenNode.children = [];
      }

      return flattenNode;
    });

  dig(treeNodeList);
  return flattenList;
}

/**
 * 获取node的位置，如在第几层的第几个
 * @param level 层级
 * @param index 索引，第几个
 */
export function getPosition(level: string | number, index: number): string {
  return `${level}-${index}`;
}

export function getKey(key: TreeNodeKey, pos: string): TreeNodeKey {
  if (key !== null && key !== undefined) {
    return key;
  }
  return pos;
}
